package com.learning.spring.cloud.ms.consumer.movie.controller;

import com.learning.spring.cloud.ms.consumer.movie.entity.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * ClassName: MovieController
 * Description:
 * Date: 2019/5/31 10:42 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@Slf4j
@RestController
@RequestMapping("movie")
public class MovieController {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 添加熔断实现。测试地址：http://localhost:8010/movie/user/1
     * <p>
     * 1- 注解 @HystrixCommand 可以设置很多属性，如命令行参数、线程池参数
     * 2- 如果有场景需要获取回退的原因，可以在 fallbackMethod 的方法上添加 Throwable 参数
     * 3- 如果有场景某些异常不想回退，有两种方式
     * 第一, hystrix 有异常 HystrixBadRequestException，这时一个特殊异常，该异常不会回退。可以自定义异常继承 HystrixBadRequestException
     * 第二, 使用 @HystrixCommand 注解的 ignoreExceptions 属性指定不想回退的异常
     *
     *
     * <p>
     * 注意：
     * 1- 当请求失败、被拒绝、超时、断路器打开，都会进入回退。
     * 2- 但是进入回退，不一定在断路器就是打开
     *
     * @param id
     * @return
     */
    @GetMapping("/user/{id}")
    @HystrixCommand(fallbackMethod = "findByIdFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")},
            threadPoolProperties = {@HystrixProperty(name = "coreSize", value = "5"), @HystrixProperty(name = "maxQueueSize", value = "10")},
            ignoreExceptions = RuntimeException.class
    )
    public User findById(@PathVariable Long id) {
        return this.restTemplate.getForObject("http://ms-provider-user/user/" + id, User.class);
    }


    /**
     * 熔断回调方法：该方法与 findById 方法需要有相同的参数与返回值类型
     *
     * @return
     */
    public User findByIdFallback(Long id, Throwable throwable) {

        log.error("访问回退：", throwable);

        User user = new User();
        user.setId(-1L);
        user.setName("默认用户");
        return user;
    }


}
